package top.milkbox.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import top.milkbox.domain.Notice;
import top.milkbox.info.NoticeInfo;
import top.milkbox.service.NoticeService;
import top.milkbox.mapper.NoticeMapper;
import org.springframework.stereotype.Service;
import top.milkbox.utils.GuoUtilsDate;
import top.milkbox.utils.GuoUtilsLog;

import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * @author xiaoguo
 * @description 针对表【tb_notice】的数据库操作Service实现
 * @createDate 2022-10-15 17:26:37
 */
@Service
public class NoticeServiceImpl extends ServiceImpl<NoticeMapper, Notice>
        implements NoticeService {

    @Autowired
    private NoticeMapper noticeMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private NoticeInfo noticeInfo;

    /**
     * 使用Redis缓存
     * 使用json方式将List存入redis
     * 1先从redis中获取数据，不管redis中有没有
     * 2如果redis中有数据则直接将数据返回
     * 3如果redis中没有数据则从数据库查询数据
     * 4查询出数据后将数据写入redis中并设置其存活时间，然后将数据返回
     *
     * @return 缓存中若由则从缓存中获取，否则从数据库中获取
     */
    @Override
    public List<Notice> getAll() {
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        String noticeListJson = opsForValue.get(noticeInfo.getAllKey());


        if (noticeListJson != null) {
            // 如果缓存中有则直接将数据返回
            List<Notice> noticeList = null;
            try {
                noticeList = objectMapper.readValue(noticeListJson, new TypeReference<List<Notice>>() {
                });
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }

            // 返回数据
            log.debug("从缓存中获取公告信息：" + GuoUtilsLog.lengthLimit(noticeList.toString()));
            return noticeList;
        } else {
            // 如果缓存中没有公告信息
            log.debug("缓存中没有公告信息，正在从数据库中查询...");

            // 返回数据
            return updateRedis();
        }

    }

    @Override
    public Boolean add(Notice notice) {
        notice.setId(null);
        notice.setTime(GuoUtilsDate.getDateNow());
        log.debug("正在添加数据：" + notice);
        if (noticeMapper.insert(notice) == 1) {
            updateRedis();
            return true;
        }
        log.error("数据库错误");
        return false;
    }

    /**
     * 立即更新缓存
     * 从数据库中查询数据放入缓存中，不管缓存中原来是否有数据
     *
     * @return 将刚刚更新的数据返回
     */
    @Override
    public List<Notice> updateRedis() {
        try {
            // 查询数据库
            QueryWrapper<Notice> wrapper = new QueryWrapper<>();
            wrapper.orderByDesc("time");
            List<Notice> noticeList = noticeMapper.selectList(wrapper);

            // 存入redis缓存，即便list的大小是0，也要存入redis
            String noticeListJson = objectMapper.writeValueAsString(noticeList);
            ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
            opsForValue.set(noticeInfo.getAllKey(), noticeListJson, noticeInfo.getAllTimeout(), TimeUnit.HOURS);
            log.debug("已更新（创建）缓存中的公告信息：" + noticeList.toString());

            // 返回数据
            return noticeList;
        } catch (JsonProcessingException e) {
            log.error("JSON转换异常");
            throw new RuntimeException(e);
        }
    }
}




